#ifndef SJRPASSWORD_IMPL_PASSWORD_HPP
#define SJRPASSWORD_IMPL_PASSWORD_HPP

SJR_NAMESPACE_BEGIN

class EpubPassword final {
public:
  constexpr static int PwdList = 4900;

  explicit EpubPassword(std::string const &path) : mContext(path), mNums() {
    auto &&index = mContext.get(PwdList);
    mNums.resize(index.size() / 4);
    memcpy(&mNums[0], &index[0], index.size());

    for (auto &&item : mNums)
      EpubLog::info("pwd id: %d", item);
  }

  ~EpubPassword() {
    mContext.put(PwdList, reinterpret_cast<unsigned char *>(&mNums[0]),
      static_cast<int>(mNums.size() * 4));
  }

  EpubPassword(EpubPassword const &) = delete;
  EpubPassword &operator=(EpubPassword const &) = delete;

  bool init(int num, char const *pwd, int len) {
    if (isExist(mNums, num))
      return false;

    mNums.push_back(num);
    auto &&h = mContext.hash256(pwd, len);
    mContext.put(num, h.data(), static_cast<int>(h.size()));
    return true;
  }

  bool verify(int num, char const *pwd, int len) {
    if (!isExist(mNums, num))
      return false;

    auto &&h = mContext.hash256(pwd, len);
    return mContext.compare(num, h.data(), static_cast<int>(h.size()));
  }

  bool change(int num, char const *srcKey, int srcKeyLen, char const *dstKey, int dstKeyLen) {
    if ((!isExist(mNums, num)) || (!this->verify(num, srcKey, srcKeyLen)))
      return false;

    auto &&h = mContext.hash256(dstKey, dstKeyLen);
    mContext.put(num, h.data(), static_cast<int>(h.size()));
    return true;
  }

private:
  EpubContext mContext;
  std::vector<int> mNums;

  static bool isExist(std::vector<int> &nums, int id) {
    bool ret = false;
    for (auto &&item : nums) {
      if (id != item)
        continue;
      ret = true;
      break;
    }
    return ret;
  }
};

SJR_NAMESPACE_END

#endif//SJRPASSWORD_IMPL_PASSWORD_HPP
